package com.unlcn.ils.kas.scheduled;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.unlcn.ils.kas.async.AsyncOrder;
import com.unlcn.ils.kas.async.DealMiddleRunnable;
import com.unlcn.ils.kas.config.DealMiddleConfig;
import com.unlcn.ils.kas.dao.mapper.erp.VJmcKasFlowInfoMapper;
import com.unlcn.ils.kas.dao.model.erp.VJmcKasFlowInfo;
import com.unlcn.ils.kas.service.constant.CronConstant;
import com.unlcn.ils.kas.service.order.SharesOrderService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * 江铃股份订单调度
 *
 * @author 罗必量
 * @since 2019-1 万磊 修改为多线程版本
 */
@Component
public class SharesOrderScheduled {

    private static final Logger LOGGER = LoggerFactory.getLogger(SharesOrderScheduled.class);

    private AtomicInteger count = new AtomicInteger(0);

    @Autowired
    private DealMiddleConfig configer;

    @Autowired
    private VJmcKasFlowInfoMapper infoMapper;

    @Autowired
    private AsyncOrder asyncOrder;

    @Autowired
    SharesOrderService service;

    /**
     * 拉取股份订单 定时任务
     **/
    // @Scheduled(initialDelay = 10000, fixedDelay = CronConstant.FIXEDDELAY)
    // 存在线程安全问题,暂时关闭 于 2019-8 改为使用 asyncDealMiddle
    @Deprecated
    public void getOrder2() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        Future<String> order1;
        Future<String> order2;
        Future<String> order3;
        Future<String> order4;

        if (!isNotPermitSynchrodataTime()) {
            LOGGER.info(simpleDateFormat.format(new Date()) + "拉取股份订单调度 start ====================");
            order1 = asyncOrder.asyncGetOrder(1);
            order2 = asyncOrder.asyncGetOrder(2);
            order3 = asyncOrder.asyncGetOrder(3);
            order4 = asyncOrder.asyncGetOrder(4);

            // 轮询异步方法状态
            Boolean notDone = true;
            while (notDone) {
                if (order1.isDone() && order2.isDone() && order3.isDone() && order4.isDone()) {
                    notDone = false;
                }
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    LOGGER.error("SharesOrderScheduled.getOrder2异常:", e);
                }
            }

            // 完成打印结束时间
            LOGGER.info(simpleDateFormat.format(new Date()) + "拉取股份订单调度 end ====================");
        }

    }

    /*
     * @Description: 异步多线程处理 v_jmc_kas_flow_info 及相关 v_jmc_kas_onway_track 中间表数据
     * 
     * @Author: zharui
     * 
     * @since 2019-8
     */
    @Scheduled(initialDelay = 1000 * 60, fixedDelay = CronConstant.FIXEDDELAY)
    public void asyncDealMiddle() {
        int rowCountPerThread = configer.getRowCountPerThread();
        int concurrentNum = configer.getConcurrentNum();
        if (!isNotPermitSynchrodataTime()) {
            LOGGER.info("处理中间表数据调度 start ====================");
            EntityWrapper<VJmcKasFlowInfo> entityWrapper = new EntityWrapper<>();
            Wrapper<VJmcKasFlowInfo> wrapper = entityWrapper.eq("bprocess", 0).orderBy("dtrefresh,vcdn");
            List<VJmcKasFlowInfo> vJmcKasFlowInfoList = infoMapper
                    .selectPage(new Page<VJmcKasFlowInfo>(1, rowCountPerThread * concurrentNum), wrapper);
            if (!vJmcKasFlowInfoList.isEmpty()) {
                int loops = Math.floorMod(vJmcKasFlowInfoList.size(), rowCountPerThread) > 0
                        ? Math.floorDiv(vJmcKasFlowInfoList.size(), rowCountPerThread) + 1
                        : Math.floorDiv(vJmcKasFlowInfoList.size(), rowCountPerThread);
                CountDownLatch countDown = new CountDownLatch(loops);
                ExecutorService executor = Executors.newCachedThreadPool();

                for (int i = 0; i < loops; i++) {
                    List<VJmcKasFlowInfo> childList = vJmcKasFlowInfoList.subList(rowCountPerThread * i,
                            Math.min(vJmcKasFlowInfoList.size(), rowCountPerThread * i + rowCountPerThread));
                    LOGGER.debug(" DealMiddle Loop ..." + i);
                    if (!childList.isEmpty()) {
                        DealMiddleRunnable runnable = new DealMiddleRunnable(countDown, childList, service);
                        executor.execute(runnable);
                    }
                }
                while (countDown.getCount() > 0) {
                    // loop,直到全部子任务线程跑完才结束
                }
            }
            this.count.incrementAndGet();
            LOGGER.info("处理中间表数据调度 end ====================");
        }
    }

    public int getInvokeDealMiddlCount() {
        return this.count.get();
    }

    /**
     * 字符串时间转calendar
     *
     * @param stTime
     * @return
     */
    private Calendar getTime(String stTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

        Date date = null;
        try {
            date = sdf.parse(stTime);
        } catch (ParseException e) {
            LOGGER.info(e.toString());
        }

        Calendar calendar = Calendar.getInstance();

        calendar.setTime(date);
        return calendar;
    }

    /*
     * @Description: 判断是否处于可作业区间(v_jmc_kas_flow_info写入时间窗口不允许作业)
     * 
     * @Author: 万磊
     */
    private Boolean isNotPermitSynchrodataTime() {
        String synchroStartTime = configer.getStartTime();
        String synchroEndTime = configer.getEndTime();
        Boolean iflag = false;
        // 当前时间
        Calendar nowCalendar = Calendar.getInstance();
        // 数据同步开时间
        Calendar startCalendar = getTime(synchroStartTime);
        // 数据结束开时间
        Calendar endCalendar = getTime(synchroEndTime);

        int nowHour = nowCalendar.get(Calendar.HOUR_OF_DAY);
        int startHour = startCalendar.get(Calendar.HOUR_OF_DAY);
        int endtHour = endCalendar.get(Calendar.HOUR_OF_DAY);

        // 处理数据的时间约等于1小时 并小于 一小时
        // 开始处理时间必须提前一小时

        if (startHour == 0) {
            if (nowHour >= 24 || nowHour <= endtHour) {
                iflag = true;
            }
        } else if (endtHour == 24) {
            if ((nowHour >= (startHour - 1)) && nowHour <= 24) {
                iflag = true;
            }
        } else {
            if ((nowHour >= (startHour - 1)) && nowHour <= endtHour) {
                iflag = true;
            }
        }
        return iflag;
    }
}
